{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Example 7: Reduction and Speed Analysis"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After building a circuit, one might want to do some stuff to **reduce the\n",
    "hardware into simpler nets** as well as **analyze various metrics of the\n",
    "hardware**. This functionality is provided in the Passes part of PyRTL\n",
    "and will demonstrated here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import pyrtl"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Part 1: Timing Analysis"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Timing and area usage** are key considerations of any hardware block that one\n",
    "makes.\n",
    "\n",
    "PyRTL provides functions to do these opertions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Creating a sample harware block\n",
    "pyrtl.reset_working_block()\n",
    "const_wire = pyrtl.Const(6, bitwidth=4)\n",
    "in_wire2 = pyrtl.Input(bitwidth=4, name=\"input2\")\n",
    "out_wire = pyrtl.Output(bitwidth=5, name=\"output\")\n",
    "out_wire <<= const_wire + in_wire2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Now we will do the timing analysis as well as print out the critical path"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Generating timing analysis information\n",
    "print(\"Pre Synthesis:\")\n",
    "timing = pyrtl.TimingAnalysis()\n",
    "timing.print_max_length()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We are also able to **print out the critical paths** as well as get them\n",
    "back as an array."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "critical_path_info = timing.critical_path()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Part 2: Area Analysis"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "PyRTL also provides **estimates for the area** that would be used up if the\n",
    "circuit was printed as an **ASIC**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "logic_area, mem_area = pyrtl.area_estimation(tech_in_nm=65)\n",
    "est_area = logic_area + mem_area\n",
    "print(\"Estimated Area of block\", est_area, \"sq mm\")\n",
    "print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Part 3: Synthesis"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Synthesis is the operation of **reducing the circuit into simpler components**\n",
    "The base synthesis function breaks down the more complex logic operations\n",
    "into logic gates (keeps registers and memories intact) as well as **reduces\n",
    "all combinatorial logic into ops that only use one bitwidth wires**\n",
    "\n",
    "This synthesis allows for PyRTL to make **optimizations to the net structure**\n",
    "as well as prepares it for further transformations on the PyRTL Toolchain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pyrtl.synthesize()\n",
    "\n",
    "print(\"Pre Optimization:\")\n",
    "timing = pyrtl.TimingAnalysis()\n",
    "timing.print_max_length()\n",
    "for net in pyrtl.working_block().logic:\n",
    "    print(str(net))\n",
    "print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Part 4: Optimization"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "PyRTL has functions built in to **eliminate unnecessary logic** from the\n",
    "circuit.\n",
    "\n",
    "These functions are all done with a simple call:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pyrtl.optimize()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Now to see the difference"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"Post Optimization:\")\n",
    "timing = pyrtl.TimingAnalysis()\n",
    "timing.print_max_length()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for net in pyrtl.working_block().logic:\n",
    "    print(str(net))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### As we can see, the number of nets in the circuit were drastically reduced by the optimization algorithm."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
